﻿/*****************************************************************************
  简介：John Leegy 重做系统后初始化的脚本
  作者：John Leegy
  操作系统：windows11
  编码：utf-8 with bom
  最近编辑时间：2025年04月26日
  其他说明：注释行宽度为78个字符
  基本理念：
 * autohotkey 2 脚本
 * 新装的系统或者ghost恢复后，运行此脚本即为平常使用的状态。
 * 尽可能多的把设置行为统一收集到此脚本中。
 * 有些行为用cmd实现较困难，所以用ahk比较好。还可使用powershell命令。
 * 尽量少用直接修改注册表的方式。使用命令。
 ******************************************************************************
 */


#Include %A_ScriptDir%  ; 为后续的 #Include 和 FileInstall 改变工作目录.

; 要设置系统，第一步就是以管理员权限运行
if not A_IsAdmin {
    Run("*RunAs " . A_AhkPath . " " . A_ScriptFullPath)
    ExitApp
}

; 系统更新反应迟钝，越早暂停越好
暂停系统更新(count) {
    ; count 年以后更新
    item :=  "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
    starttime := DateAdd(A_Now, -1, "days")
    tenYearLater := DateAdd(A_Now, 365 * count, "days")
    sta := formattime(starttime, "yyyy-MM-ddT09:09:09Z")
    end := formattime(tenYearLater, "yyyy-MM-ddT09:09:09Z")
    RegWrite("65535", "REG_DWORD" , item, "FlightSettingsMaxPauseDays")
    regwrite(sta, "REG_SZ", item, "PauseFeatureUpdatesStartTime")
    regwrite(end, "REG_SZ", item, "PauseFeatureUpdatesEndtTime")
    regwrite(sta, "REG_SZ", item, "PauseQualityUpdatesStartTime")
    regwrite(end, "REG_SZ", item, "PauseQualityUpdatesEndTime")
    regwrite(sta, "REG_SZ", item, "PauseUpdatesStartTime")
    regwrite(end, "REG_SZ", item, "PauseUpdatesExpiryTime")
}
暂停系统更新(10)

; 下面很多设置需要激活后才能进行
isOsActived(){
    activeStatus := RunWaitOne("cscript.exe /nologo C:\Windows\System32\slmgr.vbs /dli 2>&1")
    return instr(activeStatus, ": 已授权") || instr(activeStatus, ": licensed")
}
RunWaitOne(command) {
    shell := ComObject("WScript.Shell")
    ; 通过 cmd.exe 执行单条命令
    exec := shell.Exec(A_ComSpec " /C " command)
    ; 读取并返回命令的输出
    return exec.StdOut.ReadAll()
}

if !isOsActived() {
    runwait('powershell irm https://get.activated.win | iex')
    if !isOsActived() {
        msgbox "激活失败，请检查！"
        return
    }
}

;; 这里应该检测操作系统以提示使用者
if (!A_Is64bitOS || Instr("WIN_7,WIN_8,WIN_8.1,WIN_VISTA,WIN_2003,WIN_XP,WIN_2000", A_OSVersion)) {
    result := MsgBox("本脚本是在 Windows 11 64位上测试的。`n当前操作系统是" . A_OSVersion . "。`n 要继续执行吗？", , 4)
    if result = "No" {
        ExitApp
    }
}

;;假如已经存在则删除此计划任务以避免重复执行。
run('schtasks /delete /TN "initPC" /F',, "Hide")
RunWait('SCHTASKS /End /TN "LZAhk"',, "Hide")

;; 输入要使用的用户名，如果系统里没有则添加想用的用户名，同时处理计划任务。
ib := InputBox("填写要使用的用户名进行检测，`n如果取消则直接使用当前用户名！","选择用户名","T30", "lz")
if (ib.Result != "Cancel" && A_UserName != ib.Value) {
    result := msgbox("当前账号不是 " . ib.Value . "，请使用 " . ib.Value . " 重新登录。`n如果系统没有此账号现在可以添加一个。`n要现在添加 " . ib.Value . " 账户吗？",, 4)
    if ("yes" = result) {
        ;; 添加用户
        RunWait("net accounts /MAXPWAGE:UNLIMITED",,"Hide") ; 密码永不过期
        RunWait("net user " . ib.Value . " 3366 /add",, "Hide")
        RunWait("net localgroup administrators " . ib.Value . " /add",, "Hide")
    }
    ;;当以选择的用户名重启时自动运行初始化脚本
    initPC := '"' . A_AhkPath . ' ' . A_ScriptFullPath . '"'
    RunWait('schtasks /create /f /sc onlogon /tn "initPC" /tr ' . initPC,, "Hide")
    Run("logoff",, "Hide")
    ExitApp
}

;; 修改工作组
run("powershell -noprofile Add-Computer -WorkgroupName lzFamily",, "Hide")

;; 修改计算机名称。
ib1 := InputBox("给此计算机取一个名字，30 秒后使用默认值","命名此计算机","T30","lzStudy")
If (ib1.Result != "Cancel") {
    ; renameComputer(ib1.Value)
    run('powershell -noprofile Rename-Computer -NewName "' . ib1.Value . '"',, "Hide")
} 

renameComputer(name) {
    key1 := "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control"
                 . "\ComputerName\ActiveComputerName"
    key2 := "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control"
                 . "\ComputerName\ComputerName"
    key3 := "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters"
    RegWrite(name, "REG_SZ", key1, "ComputerName")
    RegWrite(name, "REG_SZ", key2, "ComputerName")
    RegWrite(name, "REG_SZ", key3, "NV Hostname")
    RegWrite(name, "REG_SZ", key3, "Hostname")
}

;; 禁止内置管理员，必须保证还有管理员账户。
if (A_IsAdmin && A_UserName != "administrator") {
    Run("net user administrator /active:no",, "Hide")
}

;; 关闭资源管理器以便修改注册表，脚本最后再打开。
runwait("taskkill /im explorer.exe /f",, "Hide")

;;禁止自动播放及相关服务。先设置以免分配盘符时自动播放。
;; 写入注册表以禁止自动播放。Win10控制面板中会同步显示。
RegWrite(1, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\"
    . "AutoplayHandlers", "DisableAutoplay")
;; 禁用自动播放通知服务
RegWrite(4, "REG_DWORD", "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\"
        . "Services\ShellHWDetection", "Start")

;;设置关机按钮功能为关机。
powerBtn := "SCHEME_BALANCED SUB_BUTTONS PBUTTONACTION"
runwait("powercfg /setacvalueindex " . powerBtn . " 3",, "Hide")
runwait("powercfg /setdcvalueindex " . powerBtn . " 3",, "Hide")
;; 显示器亮度始终100
videoLight := "SCHEME_BALANCED SUB_VIDEO aded5e82-b909-4619-9949-f5d71dac0bcb"
runWait("powercfg /setacvalueindex " . videoLight . " 100",, "Hide") 
runWait("powercfg /setdcvalueindex " . videoLight . " 100",, "Hide") 
;; 超时关闭显示器
runwait("powercfg /x monitor-timeout-dc 5",, "Hide")
runwait("powercfg /x monitor-timeout-ac 0",, "Hide")
;; 超时进入睡眠
runwait("powercfg /x standby-timeout-dc 15",, "Hide")
runwait("powercfg /x standby-timeout-ac 0",, "Hide")

; 隐藏睡眠按钮
RegWrite(1, "REG_DWORD"
    , "HKLM\SOFTWARE\Microsoft\PolicyManager\default\Start\HideSleep"
    , "value")
RegWrite(1, "REG_DWORD"
    , "HKLM\SOFTWARE\Microsoft\PolicyManager\default\Start\HideLock"
    , "value")
RegWrite(1, "REG_DWORD"
    , "HKLM\SOFTWARE\Microsoft\PolicyManager\default\Start\HideSignOut"
    , "value")

; 显示隐藏的文件
RegWrite(1, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "Hidden")
; 显示系统文件
RegWrite(1, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "ShowSuperHidden")
; 显示文件扩展名
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "HideFileExt")
; 用彩色显示加密或压缩文件
RegWrite(1, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "ShowEncryptCompressedColor")
; 设置从不合并任务栏按钮
RegWrite(2, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "TaskbarGlomLeve")
; 不显示任务栏上的搜索图标
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Search"
    , "SearchboxTaskbarMode")
; 去除任务栏上的任务视图按钮
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "ShowTaskViewButton")
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "StoreAppsOnTaskbar")
; 去掉 win10 任务栏上的 edge、资源管理器、商店、邮件图标
try RegDelete("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband"
    , "Favorites")
; 任务栏始终显示小图标
RegWrite(1, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "TaskbarSmallIcons")
; 桌面上不显示图标
RegWrite(0x40201224, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\Shell\Bags\1\Desktop"
    , "FFlags")

; 打开资源管理器时直接定位到1此电脑而不是2快速访问
RegWrite(1, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "LaunchTo")
; 隐藏资源管理器中最近使用文件和常用文件夹
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer"
    , "ShowRecent")
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer"
    , "ShowFrequent")
; 设置从不合并任务栏按钮
RegWrite(2, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
    , "TaskbarGlomLevel")
; 总是显示所有托盘图标
RegWrite(0, "REG_DWORD"
    , "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer"
    , "EnableAutoTray")

; 关闭smartScreen
RegWrite(0, "REG_DWORD"
        , "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System"
        , "SmartScreenEnabled")
RegWrite(0, "REG_DWORD"
        , "HKEY_CURRENT_USER\Software\Microsoft\Edge\SmartScreenEnabled"
        , "SmartScreenEnabled")

; 关闭 将事件写入系统日志 与 写入调试信息
RegWrite(0, "REG_DWORD"
        , "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CrashControl"
        , "LogEvent")
RegWrite(0, "REG_DWORD"
        , "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CrashControl"
        , "CrashDumpEnabled")

; 设置系统主题颜色为深色
RegWrite(0, "REG_DWORD"
        , "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
        , "SystemUsesLightTheme")
RegWrite(0, "REG_DWORD"
        , "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
        , "AppsUseLightTheme")


;; 取消系统休眠功能。也就关闭了快速启动。
RunWait("POWERCFG /HIBERNATE OFF",, "Hide")

;; 关闭提高鼠标精确度选项以便鼠标匀速运动。原来的值分别是 1，6，10
RegWrite(0, "REG_SZ", "HKCU\Control Panel\Mouse", "MouseSpeed")
RegWrite(0, "REG_SZ", "HKCU\Control Panel\Mouse", "MouseThreshold1")
RegWrite(0, "REG_SZ", "HKCU\Control Panel\Mouse", "MouseThreshold2")

;; 启用系统长路径支持能力
RegWrite(1, "REG_SZ", "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem", "LongPathsEnabled")

; 设置 ps 执行策略
run("powershell -noprofile Set-ExecutionPolicy -scope CurrentUser RemoteSigned",, "Hide")

; 调节音量
SoundSetVolume(36)

开关启动声音(0)
开关启动声音(flag := 0) {
    ;; 参数 1 表示打开系统启动声音，否则即为关闭。
    if (flag != 1) {
        flag := 0
    }
    run("mmsys.cpl")
    groupadd("声音", "声音")
    groupadd("声音", "sound")   ; 支持英文窗口
    winWait("ahk_group 声音")
    controlChooseIndex(3, "SysTabControl321", "ahk_group 声音")
    controlSetChecked(flag, "Button3", "ahk_group 声音")
    controlClick("Button6", "ahk_group 声音")
}

if (not regread("HKCU\LZ\flag\lzOSSet",, 0)){
    ; 设置开机自动登录不需要输入登录密码。先修改注册表以显示勾选项目。
    RegWrite(0, "REG_DWORD"
        , "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PasswordLess\Device"
        , "DevicePasswordLessBuildVersion")
    Run("netplwiz")
}

;; 确定脚本所在盘的盘符以便确定 wsr 位置
SplitPath(A_ScriptDir,,,,, &diskLetter)

reAssignDiskLetter()
reAssignDiskLetter() {
; 这个函数不需要重启即可重新分配盘符。按卷名分配不怕改变硬盘位置。
    if ("3659066362" != drivegetserial(diskLetter)) {
        return
    }
    if (ib1.value != "lzStudy") {
        return
    }
    ; 它的任务是是指定 wsr 目录所在盘为 targetLetter
    targetLetter := "E:"
    if (diskLetter == targetLetter) {
        return
    }

    ; 先删除 C 盘以外的所有盘符
    diskLetters := "abdefghijklmnopqrstuvwxyz" ; 注意，不能包括 C 盘。
    Loop Parse diskLetters
    {
        runwait("mountvol " . A_LoopField . ": /D")
    }
    ; 再按 VolumeName 分配盘符，这样就不怕改变硬盘位置了。
    runwait("MountVol D: \\?\Volume{1637c07c-0000-0000-0000-100000000000}\")
    global diskLetter := targetLetter
    runwait("MountVol " . diskLetter . " \\?\Volume{93abd8dc-0000-0000-0080-000000000000}\")
    runwait("MountVol F: \\?\Volume{1637c07c-0000-0000-0000-20004b000000}\")
}

/****************************************************************************
  下面设置常用目录及系统变量
  lzstudy的设置一般默认就行。
  换计算机的话，需要仔细检查各目录位置
*****************************************************************************
*/

; 设置相关目录
wsr := diskLetter . "\wsr"
; 尽量早设置 scoop 变量，因为后面很多地方要使用它。不应依赖 wsr。
scoop := wsr . "\scoop"
; 获取用户目录
userProfile := envget("USERPROFILE")

; 添加环境变量，就可以随意移动文件夹了，只需要设置这里。
runWait("setx wsr " . wsr)
; 当前脚本也需要这个变量，run 运行的可以看到。
envSet("wsr", wsr)
;; 修改工作目录到接口目录
SetWorkingDir(wsr . "\Scripts")

runwait("setx SCOOP " . scoop)
; 当前脚本也需要这个变量，run 运行的可以看到。
envSet("scoop", scoop)
runwait("setx XDG_CONFIG_HOME " scoop "\.config")
envSet("XDG_CONFIG_HOME ", scoop "\.config")
; runwait("setx SCOOP_CACHE D:\download\scoop_cache")
; makeDirJunction(userProfile "\.config"
;         , scoop . "\.config")
;; 避免 mse 实时扫描影响 scoop 安装速度。
run("powershell -noprofile Add-MpPreference -ExclusionPath '" scoop "'",, "Hide")

; 设置虚拟内存
RegWrite(diskLetter . "\pagefile.sys 0 0", "REG_MULTI_SZ", "HKEY_LOCAL_MACHINE"
        . "\SYSTEM\CurrentControlSet\Control\Session Manager"
        . "\Memory Management", "PagingFiles")

;; 运行 powershell 脚本安装驱动等。
run('powershell -noprofile -nologo -ExecutionPolicy RemoteSigned -mta -File '
        . wsr . '\Scripts\lzSetOSPs.ps1')

;; 安装小狼毫输入法
if (not regread("HKCU\LZ\flag\lzOSSet",, 0)){
    run("cmd /c " . wsr . "\Scripts\lzInstallRime.cmd")
}

; 联接火狐在用户文件夹下的配置目录。
mozillaDir := userProfile . "\AppData\Roaming\Mozilla"
; DirExist(mozillaDir) or dircreate(mozillaDir)
makeDirJunction(mozillaDir, scoop . "\persist\firefox\roaming\Mozilla")
; run(wsr . "\Program\Mozilla\Mozilla Firefox X64\firefox.exe -setDefaultBrowser")
; run(wsr . "\Program\Mozilla\Mozilla Firefox X64\firefox.exe"
;         . ' -CreateProfile "LZ ' . wsr . '\ProgramData\firefoxProfiles\lz"')
; run(scoop . "\shims\firefox.exe"
;         . ' -CreateProfile "LZ ' . scoop . '\persist\firefox\lz_profile"')

; 链接下载文件夹。warn：不行，系统不认。
; makeDirJunction(userProfile "\Downloads"
;         , "D:\Downloads")

; 微信数据文件夹，使用 sdoog 中的weixin，需要两个连接。
wxDataDir := scoop . "\persist\weixin" 
makeDirJunction(userProfile "\Documents\xwechat_files"
        ,wxDataDir . "\xwechat_files")
tencentDir := userProfile . "\AppData\Roaming\Tencent"
DirExist(tencentDir) or dircreate(tencentDir)
makeDirJunction(tencentDir . "\xwechat", wxDataDir . "\AppData")

; 链接 洛雪音乐 的数据目录
makeDirJunction(userProfile "\AppData\Roaming\lx-music-desktop"
        , wsr "\ProgramData\lx-music-desktop")

; 链接 MuseScore 的数据目录
makeDirJunction(userProfile "\Documents\MuseScore4"
        , wsr "\ProgramData\MuseScore4")
makeDirJunction(userProfile . "\AppData\Local\MuseScore"
        , scoop . "\persist\MuseScore\localMuseScore")
makeDirJunction(userProfile "\AppData\Roaming\MuseScore"
        , scoop "\persist\MuseScore\roamingMuseScore")

; 链接 libreoffice 的数据目录
makeDirJunction(userProfile "\AppData\Roaming\LibreOffice"
        , wsr "\ProgramData\LibreOffice")

; 链接 zyfun 的数据目录
makeDirJunction(userProfile "\AppData\Roaming\zyfun"
        , wsr "\ProgramData\zyfun")

; 链接 onlyoffice 的数据目录
makeDirJunction(userProfile "\AppData\local\ONLYOFFICE"
        , wsr "\ProgramData\ONLYOFFICE")

; 链接totalcommander 下的 imagine
makeDirJunction(wsr "\Program\TotalCMD\Plugins\Wlx\Imagine"
        , wsr "\Program\TotalCMDTools\Imagine")

; 链接 powershell 配置文件目录
makeDirJunction(userProfile "\Documents\WindowsPowerShell"
        , wsr "\Scripts\PsProfile")
makeDirJunction(userProfile "\Documents\PowerShell"
        , wsr "\Scripts\PsProfile")

; 注册 vlc 安装目录以供 obs 使用
RegWrite("E:\wsr\scoop\apps\vlc\current", "REG_SZ"
        , "HKEY_LOCAL_MACHINE\SOFTWARE\VideoLAN\VLC", "InstallDir")

; 设置命令行提示符同时发送cwd信息
PROMPT := "$e]9;9;$P$e\$e[44mCMD$e[40m$e[32m$s$p$_$g$s$e[0m"
runWait("setx PROMPT " . PROMPT)
envSet("prompt", PROMPT)

;; 添加计划任务以便每次启动电脑时运行AutoHotkey
;; 命令行添加无法设置电源条件。只好写一个函数。
addAHKToTaskSchedule("LZAhk")
;; 运行此计划任务
Run('SCHTASKS /Run /TN "LZAhk"')

; 做一个完成设置的记号。
RegWrite(1, "REG_DWORD", "HKCU\LZ\flag\lzOSSet")

; 重新启动资源管理器使注册表更改生效
run("explorer.exe",, "Hide")

; MsgBox("初始化完成!")

return

; 添加计划任务的函数
; cmd命令schtasks无法设置电源条件。
addAHKToTaskSchedule(taskName) {
    service := ComObject("Schedule.Service")
    service.Connect()
    rootFolder := service.GetFolder("\")
    taskDefinition := service.NewTask(0)

    regInfo := taskDefinition.RegistrationInfo
    regInfo.Description := "运行 AutoHotkey 热键脚本"
    regInfo.Author := A_UserName

    principal := taskDefinition.Principal
    principal.LogonType := 3
    principal.RunLevel := 1
    principal.UserId := A_UserName

    settings := taskDefinition.Settings
    settings.Enabled := True
    settings.Hidden := False
    settings.DisallowStartIfOnBatteries := False

    triggers := taskDefinition.Triggers
    trigger := triggers.Create(9)
    trigger.UserId := A_UserName
    trigger.Enabled := True
    ;trigger.Delay := "PT30S"
    ;registrationTrigger := triggers.Create(7)
    ;registrationTrigger.Enabled := True

    Action := taskDefinition.Actions.Create(0)
    ; 设置盘符改变了，所以这里使用变量指明路径
    Action.Path := scoop . "\shims\AutoHotkey.exe"
    Action.Arguments := wsr . "\Scripts\ahk\hotkey.ahk"

    rootFolder.RegisterTaskDefinition(taskName, taskDefinition, 6,"","", 3)
}

; 这个创建联接函数会删除先前存在的目录，这是有风险的，但保证了创建连接的成功
makeDirJunction(link, target) {
    ; 建立目录连接。
    if not inStr(fileExist(target), "D") {
        MsgBox("此目标目录不存在，无法创建链接。`n" . target)
        return
    }
    ;如果连接或者目录已经存在就删除后创建，保证成功创建连接。
    flag := fileExist(link)
    if (instr(flag, "L")) {
        dirdelete(link, "r")
    } else if (flag) {
        DirMove(link, link . ".lzbak", "2")
    }
    mklink := 'mklink /J "' . link . '" "' . target . '"'
    runwait(A_ComSpec . " /c " . mklink,, "Hide")
}
